package com.jianjun.project.system.login;

import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.math.Calculator;
import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Method;
import com.jfinal.aop.Clear;
import com.jfinal.aop.Inject;
import com.jfinal.core.ActionKey;
import com.jfinal.core.Controller;
import com.jfinal.core.Path;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.ThreadPoolKit;
import com.jfinal.plugin.ehcache.UtilCache;
import com.jianjun.common.constant.CacheConstants;
import com.jianjun.common.constant.Constants;
import com.jianjun.common.util.AllConfig;
import com.jianjun.common.util.SecurityUtils;
import com.jianjun.framework.manager.factory.AsyncFactory;
import com.jianjun.framework.security.LoginBody;
import com.jianjun.framework.security.LoginUser;
import com.jianjun.framework.security.RegisterBody;
import com.jianjun.framework.security.service.SysPermissionService;
import com.jianjun.framework.security.service.SysRegisterService;
import com.jianjun.framework.security.service.TokenService;
import com.jianjun.framework.web.domain.AjaxResult;
import com.jianjun.framework.web.interceptor.JwtAuthenticationTokenInterceptor;
import com.jianjun.project.common.model.SysMenu;
import com.jianjun.project.common.model.SysUser;
import com.jianjun.project.system.config.SysConfigService;
import com.jianjun.project.system.menu.SysMenuService;

import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * 登录验证
 *
 * @author source
 */
@Path(value = "/noPath")
public class SysLoginController extends Controller {
    private final String captchaType = AllConfig.CONFIG.get("common.captchaType");
    private final String captchaInterfere = AllConfig.CONFIG.get("common.captchaInterfere");
    @Inject
    SysLoginService loginService;
    @Inject
    SysPermissionService permissionService;
    @Inject
    TokenService tokenService;
    @Inject
    SysMenuService menuService;
    @Inject
    SysConfigService configService;
    @Inject
    SysRegisterService registerService;

    @ActionKey("/captchaImage")
    @Clear(JwtAuthenticationTokenInterceptor.class)
    public void getCode() {
        AjaxResult ajax = AjaxResult.success();
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        ajax.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled) {
            renderJson(ajax);
            return;
        }
        // 保存验证码信息
        String uuid = IdUtil.fastSimpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        String code, imgBase64;

        // 生成验证码
        if ("math".equals(captchaType)) {
            AbstractCaptcha captcha;
            switch (captchaInterfere) {
                case "circle":
                    captcha = CaptchaUtil.createCircleCaptcha(160, 60);
                    break;
                case "shear":
                    captcha = CaptchaUtil.createShearCaptcha(160, 60);
                    break;
                case "gif":
                    captcha = CaptchaUtil.createGifCaptcha(160, 60);
                    break;
                default:
                    captcha = CaptchaUtil.createLineCaptcha(160, 60);
                    break;
            }

            // 自定义验证码内容为四则运算方式
            captcha.setGenerator(new MathGenerator(1));
            // 重新生成code
            captcha.createCode();
            code = Convert.toStr((int) Calculator.conversion(captcha.getCode()));
            imgBase64 = captcha.getImageBase64();
        } else if ("char".equals(captchaType)) {
            //定义图形验证码的长、宽、验证码字符数、干扰元素个数
            AbstractCaptcha captcha;
            switch (captchaInterfere) {
                case "circle":
                    captcha = CaptchaUtil.createCircleCaptcha(160, 60, 4, 4);
                    break;
                case "shear":
                    captcha = CaptchaUtil.createShearCaptcha(160, 60, 4, 4);
                    break;
                case "gif":
                    captcha = CaptchaUtil.createGifCaptcha(160, 60, 4);
                    break;
                default:
                    captcha = CaptchaUtil.createLineCaptcha(160, 60, 4, 4);
                    break;
            }
            code = captcha.getCode();
            imgBase64 = captcha.getImageBase64();
        } else {
            renderJson(AjaxResult.error("类型不支持"));
            return;
        }
        UtilCache.setex(verifyKey, Constants.CAPTCHA_EXPIRATION * DateUnit.MINUTE.getMillis() / DateUnit.SECOND.getMillis(), code);
        ajax.put("uuid", uuid);
        ajax.put("img", imgBase64);
        renderJson(ajax);
    }

    /**
     * 登录方法
     */
    @ActionKey("/login")
    @Clear(JwtAuthenticationTokenInterceptor.class)
    public void login() {
        LoginBody loginBody = JsonKit.parse(getRawData(), LoginBody.class);
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        renderJson(ajax);
    }

    /**
     * 获取用户信息
     *
     */
    @ActionKey("/getInfo")
    public void getInfo() {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser user = loginUser.getUser();
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);
        if (!loginUser.getPermissions().equals(permissions)) {
            loginUser.setPermissions(permissions);
            tokenService.refreshToken(loginUser);
        }
        AjaxResult ajax = AjaxResult.success();
        ajax.put("user", user);
        ajax.put("roles", roles);
        ajax.put("permissions", permissions);
        renderJson(ajax);
    }

    @ActionKey("/logout")
    @Clear(JwtAuthenticationTokenInterceptor.class)
    public void logout() {
        LoginUser loginUser = tokenService.getLoginUser(getRequest());
        if (Objects.nonNull(loginUser)) {
            String userName = loginUser.getUser().getUserName();
            // 删除用户缓存记录
            tokenService.delLoginUser(loginUser.getToken());
            // 记录用户退出日志
            ThreadPoolKit.execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
        }
        renderJson(AjaxResult.success("退出成功"));
    }

    /**
     * 获取路由信息
     *
     */
    @ActionKey("/getRouters")
    public void getRouters() {
        Long userId = SecurityUtils.getUserId();
        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
        renderJson(AjaxResult.success(menuService.buildMenus(menus)));
    }


    @ActionKey("/upload")
    @Clear(JwtAuthenticationTokenInterceptor.class)
    public void upload() {
        String path = URLDecoder.decode(ResourceUtil.getResource("static/upload").getPath(), StandardCharsets.UTF_8);
        if (path.startsWith("/") && path.contains(":")) {
            path = path.replaceFirst("/", "");
        }
        renderFile(Paths.get(path, getPara()).toFile());
    }

    @ActionKey("/")
    @Clear(JwtAuthenticationTokenInterceptor.class)
    public void indexHtml() {
        String method = getRequest().getMethod();
        if (Method.GET.name().equals(method) && StrUtil.isEmpty(getRawData()) && getKv().isEmpty()) {
            String htmlStr = ResourceUtil.readUtf8Str("static/index.html");
            renderHtml(htmlStr);
        }
    }

    @ActionKey("/register")
    @Clear(JwtAuthenticationTokenInterceptor.class)
    public void register() {
        RegisterBody user = JsonKit.parse(getRawData(), RegisterBody.class);
        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
            renderJson(AjaxResult.error("当前系统没有开启注册功能！"));
            return;
        }
        String msg = registerService.register(user);
        renderJson(StrUtil.isEmpty(msg) ? AjaxResult.success() : AjaxResult.error(msg));
    }
}
